#include "stdafx.h"

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
	switch (Message)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);
	}

	return 0;
}

HINSTANCE Game::hinst;

Game::Game()
{
	WNDCLASSEX wc = { 0 };
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.hCursor = LoadCursor(hinst, IDC_ARROW);
	wc.hIcon = wc.hIconSm = LoadIcon(hinst, IDI_APPLICATION);
	wc.hInstance = hinst;
	wc.lpfnWndProc = WndProc;
	wc.lpszClassName = L"Window";
	RegisterClassEx(&wc);
	hwnd = CreateWindowEx(0, L"Window", L"tank", WS_POPUP, 0, 0, XSCREEN, YSCREEN, NULL, NULL, hinst, NULL);
	UpdateWindow(hwnd);
	ShowWindow(hwnd, 1);
	//create graphics in memory
	BITMAPINFO bmi = { sizeof(bmi),XSCREEN,YSCREEN,1,32, };
	hdc = GetDC(hwnd);
	memDC = CreateCompatibleDC(hdc);
	HBITMAP bmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
	SelectObject(memDC, bmp);
	DeleteObject(bmp);
	graphics = new Graphics(memDC);

	Map::setHDC(hdc);

	//about time
	QueryPerformanceFrequency(&frequency);
	QueryPerformanceCounter(&startcount);
	time = 0;

	//wall = new Wall(hdc, L"img\\wall.png");
	//hero = new HeroTank(L"img\\hero", 600, 300, DIR_UP, 10);
	//EnemyMgr::getInstance()->create(L"img\\enemy1", 600, 300, 100, 10);
	PropertyMgr::getInstance()->create(L"Timer", 400, 300);
	PropertyMgr::getInstance()->create(L"Star", 500, 300);
	PropertyMgr::getInstance()->create(L"Bomb", 600, 400);
}

Game::~Game()
{
	//delete wall;
	delete levelcircle;
	delete hero;
	ReleaseDC(hwnd, hdc);
	delete graphics;
	DeleteDC(memDC);
}

Game * Game::getInstance()
{
	static Game inst;

	return &inst;
}

int Game::loop()
{
	MSG msg;

	do
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			if (!frame())
			{
				DestroyWindow(hwnd);
			}
		}
	} while (msg.message != WM_QUIT);

	return msg.wParam;
}

bool Game::frame()
{
	// Font **********************************************************************************
	static FontFamily ffm{ L"Consolas" };
	static Font font{ &ffm,13 };
	static SolidBrush textBrush{ 0xffffffff };
	static FontFamily ffmstatus{ L"Consolas" };
	static Font fontstatus{ &ffmstatus,20 };
	// Time **********************************************************************************
	static LARGE_INTEGER lastCounter = startcount;
	static UINT nCounter = 0;

	LARGE_INTEGER currentCounter;
	QueryPerformanceCounter(&currentCounter);

	time = (double)(currentCounter.QuadPart - startcount.QuadPart) / frequency.QuadPart;
	double deltaTime = (double)(currentCounter.QuadPart - lastCounter.QuadPart) / frequency.QuadPart;
	FPS = 1.0 / deltaTime;
	lastCounter = currentCounter;

	// Keyboard Input ************************************************************************
	static bool lastkey[256] = { 0 };
	bool curkey[256];
	POINT curpt;

	GetCursorPos(&curpt);

	for (int i = 0; i < 256; i++)
	{
		curkey[i] = GetAsyncKeyState(i) < 0;
		if (curkey[i])
		{
			switch (scene)
			{
			case 0:
				break;
			case 1:
				break;
			case 2:
				if (!stop)
				{
					hero->update(deltaTime);
					/*switch (i)
					{
					case VK_LEFT:
						hero->move(-5, 0);
						if (Map::getInstance()->collide(hero->getRect()) || EnemyMgr::getInstance()->collide(hero->getRect()))
						{
							hero->move(5, 0);
							hero->changeDir(DIR_LEFT);
						}
						break;
					case VK_RIGHT:
						hero->move(5, 0);
						if (Map::getInstance()->collide(hero->getRect()) || EnemyMgr::getInstance()->collide(hero->getRect()))
						{
							hero->move(-5, 0);
							hero->changeDir(DIR_RIGHT);
						}
						break;
					case VK_UP:
						hero->move(0, -5);
						if (Map::getInstance()->collide(hero->getRect()) || EnemyMgr::getInstance()->collide(hero->getRect()))
						{
							hero->move(0, 5);
							hero->changeDir(DIR_UP);
						}
						break;
					case VK_DOWN:
						hero->move(0, 5);
						if (Map::getInstance()->collide(hero->getRect()) || EnemyMgr::getInstance()->collide(hero->getRect()))
						{
							hero->move(0, -5);
							hero->changeDir(DIR_DOWN);
						}
						break;
					}*/
				}
				break;
			}
			
		}
		if (curkey[i] && !lastkey[i])														//keydown
		{
			switch (scene)
			{
			case 0:
				switch (i)
				{
				case VK_LBUTTON:
					if (curpt.x > NEWGAME.left && curpt.x < NEWGAME.right && curpt.y > NEWGAME.top && curpt.y < NEWGAME.bottom)		//new game
					{
						MessageBox(NULL, L"new game", L"game", MB_OK);
						levelcircle = new LevelCircle(L"circle", XBLANK + 50, YBLANK + 50);
						scene = 1;
					}
					else if (curpt.x > READSAVING.left && curpt.x < READSAVING.right && curpt.y>READSAVING.top && curpt.y < READSAVING.bottom)	//read saving
					{
						MessageBox(NULL, L"read saving", L"game", MB_OK);
					}
					else if (curpt.x > QUIT.left && curpt.x < QUIT.right && curpt.y>QUIT.top && curpt.y < QUIT.bottom)	//quit
					{
						MessageBox(NULL, L"quit", L"game", MB_OK);
					}
					break;
				}
				break;
			case 1:
				switch (i)
				{
				case VK_LBUTTON:
					for (int i = 0; i < MAXROW; i++)
					{
						for (int j = 0; j < MAXLINE; j++)
						{
							if (i * MAXLINE + j < curMaxLevel)
							{
								int x = XBLANK + j*XGAP;
								int y = YBLANK + i*YGAP;
								if (curpt.x > x && curpt.x<x + 100 && curpt.y>y && curpt.y < y + 100)
								{
									level = i * MAXLINE + j + 1;
									//**initialize level
									LevelMgr::getInstance()->loadLevel(level);
									scene = 2;
								}
							}
							
							
						}
					}
					break;
				}
				break;
			case 2:
				switch (i)
				{
				case 'J':
					if (!stop)
					{
						hero->launch(L"DotBullet", heroBulletNormal);
					}
					break;
				case 'K':
					if (!stop)
					{
						if (hero->getBomb() > 0)
						{
							hero->launch(L"Missile", heroBulletBomb);
							hero->bombBy(-1);
						}
					}
					break;
				case VK_LBUTTON:
					if (dlg)
					{
						switch (dlg->getcmd(curpt.x - dlg->x + dlg->width / 2, curpt.y - dlg->y + dlg->height / 2))
						{
						case 1:			//quit
							//**save game
							DestroyWindow(hwnd);
							delete dlg;
							dlg = nullptr;
							break;
						case 2:			//return
							scene = 1;
							delete dlg;
							dlg = nullptr;
							stop = false;
							break;
						case 3:			//restart
							LevelMgr::getInstance()->loadLevel(level);
							delete dlg;
							dlg = nullptr;
							stop = false;
							break;
						case 4:			//next level
							LevelMgr::getInstance()->loadLevel(++level);
							delete dlg;
							dlg = nullptr;
							stop = false;
							break;
						}
					}
					break;
				}
				break;
			}
			
		}
		else if (!curkey[i] && lastkey[i])
		{

		}
		lastkey[i] = curkey[i];
	}
	// Mouse Input ***************************************************************************
	/*static POINT lastpt = { 0 };
	POINT curpt;

	GetCursorPos(&curpt);
	if(curpt.x!=)*/

	// Draw **********************************************************************************

	switch (scene)
	{
	case 0:													//startup page
		//**draw background here
		//**draw buttons
		break;
	case 1:													//choosing level page
	{
		//static std::wstring pre1 = L"img\\level";
		//static std::wstring pre2 = L"img\\ui";
		bool hit = false;
		int hitx, hity;
		wchar_t hittype;

		graphics->Clear(0xff000000);
		graphics->DrawImage(ImageMgr::getInstance()->getImageFromName(L"img\\back.png"), -230, 0, XSCREEN + 230, YSCREEN);

		for (int i = 0; i < MAXROW; i++)
		{
			for (int j = 0; j < MAXLINE; j++)
			{
				if (i * MAXLINE + j < curMaxLevel)
				{
					
					std::wstring temp = L"img\\level";
					temp = temp + LEVEL[i][j] + L".png";

					int x = XBLANK + j*XGAP;
					int y = YBLANK + i*YGAP;
					if (i*MAXLINE + j == curMaxLevel - 1)
					{
						levelcircle->moveto(x + 50, y + 50);
					}
					if (curpt.x > x && curpt.x<x + 100 && curpt.y>y && curpt.y < y + 100)
					{
						hitx = j;
						hity = i;
						hit = true;
						hittype = LEVEL[i][j];
					}
					graphics->DrawImage(ImageMgr::getInstance()->getImageFromName(temp), x, y, 100, 100);
				}
				
			}
		}
		if (hit)
		{
			std::wstring temp = L"img\\ui";
			temp = temp + hittype + L".png";
			int x = XBLANK + hitx*XGAP;
			int y = YBLANK + hity*YGAP;
			graphics->DrawImage(ImageMgr::getInstance()->getImageFromName(temp), x, y - 1, 335, 223);

			int level = hitx*MAXLINE + hity;
			graphics->DrawString(LevelMgr::getInstance()->getCommentString(level).c_str(), -1, &font, PointF(x + 40, y + 120), &textBrush);
		}
		//DOMgr::getInstance()->update(deltaTime);
		//DOMgr::getInstance()->draw(graphics);
		levelcircle->update(deltaTime);
		levelcircle->draw(graphics);

		break;
	}
	case 2:
		if (wins->win() && !stop)										//win the level
		{
			//MessageBox(NULL, L"win", L"", MB_OK);
			dlg = new WinDlg(L"win", XSCREEN / 2, YSCREEN / 2);
			stop = true;
			curMaxLevel = max(level + 1, curMaxLevel);
		}
		if (wins->lose() && !stop)										//lose the level
		{
			//MessageBox(NULL, L"lose", L"", MB_OK);
			dlg = new FailDlg(L"fail", XSCREEN / 2, YSCREEN / 2);
			stop = true;
		}

		graphics->Clear(0xff000000);

		if (!stop)
		{
			EnemyMgr::getInstance()->update(deltaTime);
			PropertyMgr::getInstance()->update(deltaTime);
		}

		Map::getInstance()->getWall()->draw(memDC);
		Map::getInstance()->getSteel()->draw(memDC);
		Map::getInstance()->getWater()->draw(memDC);

		hero->draw(graphics);

		BulletMgr::getInstance()->update(deltaTime);
		BulletMgr::getInstance()->draw(graphics);

		EnemyMgr::getInstance()->draw(graphics);

		AnimationMgr::getInstance()->update(deltaTime);
		AnimationMgr::getInstance()->draw(graphics);

		PropertyMgr::getInstance()->draw(graphics);

		CollectionMgr::getInstance()->update(deltaTime);
		CollectionMgr::getInstance()->draw(graphics);

		if (endpoint)
		{
			endpoint->update(deltaTime);
			endpoint->draw(graphics);
		}

		wchar_t temp[500] = { 0 };
		swprintf_s(temp, L"Life:%d\n\nBomb:%d\n\nPower:%d\n\n\n\nRemaining Enemy:%d", hero->getLife(), hero->getBomb(), hero->getPower(), EnemyMgr::getNum());
		graphics->DrawString(temp, -1, &fontstatus, PointF(LEFTMAP + WIDTHMAP + 50, TOPMAP + 50), &textBrush);
		graphics->FillRectangle(&textBrush, LEFTMAP + WIDTHMAP + 100, TOPMAP + 600, 150, 70);
		graphics->FillRectangle(&textBrush, LEFTMAP + WIDTHMAP + 120, TOPMAP + 550, 110, 50);
		graphics->FillRectangle(&textBrush, LEFTMAP + WIDTHMAP + 30, TOPMAP + 565, 90, 15);

		if (dlg)
		{
			dlg->update(deltaTime);
			dlg->draw(graphics);
		}

		break;
	}
	
	//static TCHAR temp[100];
	//swprintf_s(temp, L"FPS:%6lf Time:%6lf", FPS, time);
	//TextOut(memDC, 0, 0, temp, _tcslen(temp));
	//****************************************************************************************
	BitBlt(hdc, 0, 0, XSCREEN, YSCREEN, memDC, 0, 0, SRCCOPY);
	
	return true;
}

HeroTank * Game::getHero()
{
	return hero;
}

void Game::sethInstance(HINSTANCE hInstance)
{
	hinst = hInstance;
}

void Game::setStrategy(GameStrategy * s)
{
	wins = s;
}

void Game::deleteHero()
{
	if (hero)
	{
		delete hero;
		hero = nullptr;
	}
}

void Game::newHero(HeroTank * h)
{
	hero = h;
}

void Game::newGame()
{
	AnimationMgr::getInstance()->clear();
	BulletMgr::getInstance()->clear();
	EnemyMgr::getInstance()->clear();
	PropertyMgr::getInstance()->clear();
	CollectionMgr::getInstance()->clear();
	time = 0;

	if (dlg)
	{
		delete dlg;
		dlg = nullptr;
	}

	if (endpoint)
	{
		delete endpoint;
		endpoint = nullptr;
	}

	if (hero)
	{
		delete hero;
		hero = nullptr;
	}
}